// =====================================================================================
// 
//       Filename:  ast.h
// 
//    Description:  Définition des arbres de syntaxe abstraite, utilisés pour la
//    				résolution des expressions mathématiques
// 
//        Version:  1.0
//        Created:  04/10/2009 23:15:17
//       Revision:  none
//       Compiler:  g++
// 
//         Author:  François Hissel (fh), francois.hissel@m4x.org
//        Company:  
// 
// =====================================================================================

#ifndef  AST_H_INC
#define  AST_H_INC

#include	<string>
#include	<exception>

using namespace std;

/**
 * \namespace AST
 * \brief Ensemble des données de gestion des arbres de syntaxe abstraite
 *
 * L'espace de noms contient des définitions de types, des classes et des structures utilisées pour la gestion des arbres de syntaxe abstraite, comprenant notamment des fonctions de lecture de ces arbres à partir de flux d'entrée, d'évaluation de ces arbres, et de création de modèles compilés d'évaluation rapide.
 * La grammaire utilisée pour définir les arbres de syntaxe abstraite est définie dans \ref parserdoc.
 */
namespace AST {

/***********************************/
/* DEFINITION DES TYPES DE DONNEES */
/***********************************/
class Value;

/**
 * \enum Type
 * \brief Définition des types de données que peuvent contenir les expressions
 *
 * L'énumération définit les différents types de données que peut retouner l'évaluation d'un arbre de syntaxe abstraite.
 */
enum Type {
	NUL=0,	//!< Aucun type ou type inconnu
	DOUBLE=1,	//!< Type flottant
	INTEGER=2,	//!< Type entier
	STRING=3,	//!< Type chaîne de caractères
	BOOLEAN=4	//!< Type booléen
};

typedef Value (*LookupFunction)(const string &name,const void* data);	//!< Pointeur vers une fonction d'accès à une variable. Le type est utilisé pour spécifier une fonction d'évaluation d'une variable lors de l'évaluation d'un arbre syntaxique.

/*****************************/
/* DEFINITION DES EXCEPTIONS */
/*****************************/
/**
 * \class ASTException
 * \brief Exception soulevée lorsqu'une erreur survient pendant une opération sur les arbres de syntaxe abstraite, en utilisant l'une des classes de l'espace de noms AST
 *
 * La classe permet de gérer les erreurs qui surviennent pendant les opérations sur les arbres de syntaxe abstraite.
 */
class ASTException:public exception {
	public:
		/**
		 * \brief Ensemble des codes d'erreur possibles
		 *
		 * L'énumération rassemble les codes d'erreur qui peuvent être retournés lorsqu'une opération sur les arbres de syntaxe abstraite a généré une erreur.
		 */
		enum Code {
			BAD_TYPE=1,	//!< Erreur de type de données
			SYNTAX_ERROR=2,	//!< Erreur de syntaxe dans une expression
			UNKNOWN_FUNCTION=3	//!< Fonction ou variable inconnue
			} code;	//!< Code de l'erreur
		string message;	//!< Message descriptif de l'erreur
		ASTException(Code pcode):code(pcode) {}	//!< Constructeur sans définition du message
		ASTException(Code pcode,string pmessage):code(pcode),message(pmessage) {}	//!< Constructeur avec définition du message
		~ASTException() throw() {}	//!< Destructeur standard
		const char* what() const throw();	//!< Retourne un message de description de l'erreur
};

/************************************************/
/* DEFINITION DES STRUCTURES D'ARBRE SYNTAXIQUE */
/************************************************/
/**
 * \class SyntaxNode
 * \brief Classe générique pour la représentation d'un noeud d'un arbre de syntaxe abstraite
 *
 * La classe représente un noeud syntaxique d'une expression, constitué soit par une valeur seule, soit par une opération sur plusieurs valeurs qui sont alors les enfants du noeud dans l'arbre syntaxique. Elle est abstraite et ne peut être instanciée que par l'intermédiaire d'une de ses classes dérivées Function ou Value.
 */
class SyntaxNode {
	public:
		virtual ~SyntaxNode() {}	//!< Destructeur standard, virtuel abstrait

		/**
		 * \brief Evalue l'expression contenue dans l'arbre et retourne la valeur correspondante
		 *
		 * La fonction évalue l'expression contenue dans l'arbre, qu'il s'agisse d'un simple terme ou d'une expression plus complexe, puis retourne sa valeur sous la forme d'une variable typée de type Value. Le type étant connu, la valeur de l'expression peut alors être obtenue en appelant l'un des accesseurs get_XXX de la classe Value.
		 * \param lookup Fonction de recherche d'une variable dans une base de données
		 * \param data Pointeur vers la base de données des variables, utilisé en paramètre de la fonction lookup
		 * \return Classe contenant la valeur du sous-arbre courant et son type
		 */
		virtual Value get_value(LookupFunction lookup=0,const void *data=0) const=0;

		/**
		 * \brief Retourne le type de valeurs contenu
		 *
		 * La fonction retourne le type de données représenté par l'expression contenue dans le sous-arbre courant.
		 * \param lookup Fonction de recherche d'une variable dans une base de données
		 * \param data Pointeur vers la base de données des variables, utilisé en paramètre de la fonction lookup
		 * \return Type de données du sous-arbre
		 */
		virtual Type get_type(LookupFunction lookup=0,const void *data=0) const=0;
};

/**
 * \class Value
 * \brief Représentation d'une valeur avec le type de données correspondant
 *
 * La classe représente une valeur typée. Elle est utilisée comme résultat de l'évaluation d'un arbre de syntaxe abstraite. Le stockage du type permet de vérifier la validité des opérations effectuées, voire de définir des comportements différents pour des types de données différents.
 */
class Value:public SyntaxNode {
	public:
		Value():_type(NUL),_size(0),_data(0) {}	//!< Constructeur standard
		Value(double pval);	//!< Constructeur d'une structure de type flottant
		Value(int pval);	//!< Constructeur d'une structure de type entièr
		Value(const string &pval);	//!< Constructeur d'une structure de type chaîne de caractères
		Value(bool pval);	//!< Constructeur d'une structure de type booléen
		Value(const Value& pval);	//!< Constructeur de copie
		virtual ~Value();	//!< Destructeur standard, libère la mémoire allouée au stockage de la variable contenue

		/**
		 * \brief Opérateur d'affectation d'une valeur à une autre
		 * 
		 * La fonction affecte le contenu de la variable spécifiée en argument à l'instance. Si l'instance contient déjà une valeur, celle-ci est d'abord détruite et la mémoire associée est libérée. La structure de donnée est alors recopiée dans l'instance.
		 */
		void operator=(const Value &pval);

		/**
		 * \brief Retourne une copie de la valeur courante
		 *
		 * La fonction ne fait que retourner une copie de l'instance courante. Elle implémente la fonction héritée de la classe SyntaxNode.
		 * \param lookup Fonction de recherche dans une base de données, non utilisée
		 * \param data Base de données de recherche des variables, non utilisée
		 * \return Copie de la valeur courante
		 */
		virtual Value get_value(LookupFunction lookup=0,const void *data=0) const {return *this;}

		/**
		 * \brief Retourne le type de la valeur contenue
		 *
		 * La fonction retourne le type de son contenu. Voir aussi SyntaxNode::get_type.
		 * \param lookup Fonction de recherche dans une base de données, non utilisée
		 * \param data Base de données de recherche des variables, non utilisée
		 * \return Type de données représenté par la valeur
		 */
		Type get_type(LookupFunction lookup=0,const void *data=0) const {return _type;}

		double get_double() const; 	//!< Retourne la valeur flottante contenue dans la structure
		int get_integer() const;	//!< Retourne la valeur entière contenue dans la structure
		string get_string() const; 	//!< Retourne la chaîne de caractères contenue dans la structure
		bool get_boolean() const; 	//!< Retourne la valeur booléenne contenue dans la structure
	private:
		Type _type;	//!< Type de données contenues dans la classe
		unsigned short _size;	//!< Taille des données en mémoire	
		char* _data;	//!< Stockage des données en mémoire
};

/**
 * \class Function
 * \brief Représentation d'une fonction de plusieurs valeurs
 *
 * La classe héritée de SyntaxNode est la représentation arborescente d'une fonction agissant sur un nombre quelconque d'arguments.
 */
class Function:public SyntaxNode {
	public:
		/**
		 * \brief Constructeur d'une fonction sans argument
		 *
		 * Le constructeur initialise un objet Function sans argument, mais en définissant le nombre d'arguments. Les arguments devront être fournis par la méthode Function::add_children.
		 * \param pname Nom de la fonction
		 * \param pargs Nombre d'arguments
		 */
		Function(const string &pname,unsigned char pargs);

		/**
		 * \brief Constructeur d'une fonction sans argument (ou une variable)
		 *
		 * Le constructeur initialise un objet Function sans argument. Cet objet est utilisé pour représenter une variable.
		 * \param pname Nom de la fonction ou de la variable
		 */
		Function(const string &pname):_cur_child(0),_nbchildren(0),_name(pname) {}

		/**
		 * \brief Constructeur d'une fonction unaire
		 *
		 * Le constructeur initialise un objet Function correspondant à une fonction unaire.
		 * \param pname Nom de la fonction unaire
		 * \param arg Pointeur vers l'argument
		 */
		Function(const string &pname,SyntaxNode *arg);

		/**
		 * \brief Constructeur d'une fonction binaire
		 *
		 * Le constructeur initialise un objet Function correspondant à une fonction binaire.
		 * \param pname Nom de la fonction binaire
		 * \param arg1 Pointeur vers le premier argument
		 * \param arg2 Pointeur vers le second argument
		 */
		Function(const string &pname,SyntaxNode *arg1,SyntaxNode *arg2);

		virtual ~Function();	//!< Destructeur standard, libère la mémoire associée à l'objet

		/**
		 * \brief Ajoute un argument à la fonction
		 * 
		 * La fonction définit l'argument suivant de l'instance.
		 * \param parg Arbre syntaxique représentant l'argument suivant
		 */
		void add_child(SyntaxNode *parg) {if (_cur_child<_nbchildren) _children[_cur_child++]=parg;}

		/**
		 * \brief Evalue les arguments puis calcule la valeur de la fonction
		 *
		 * La fonction évalue chacun des arguments contenus dans les enfants du noeud courant, puis calcule la valeur de la fonction et la retourne sous la forme d'une classe Value. Elle implémente la fonction héritée SyntaxNode::get_value(). Les fonctions reconnues sont définies dans \ref parserdoc.
		 * \param lookup Fonction de recherche d'une variable dans une base de données
		 * \param data Base de données de recherche des variables, utilisée en paramètre de la fonction lookup
		 * \return Classe contenant la valeur de la fonction évaluée et son type
		 */
		virtual Value get_value(LookupFunction lookup=0,const void *data=0) const;

		/**
		 * \brief Retourne le type de la valeur contenue
		 *
		 * La fonction retourne le type de son contenu. Voir aussi SyntaxNode::get_type.
		 * \param lookup Fonction de recherche d'une variable dans une base de données
		 * \param data Base de données de recherche des variables, utilisée en paramètre de la fonction lookup
		 * \return Type de données représenté par la valeur
		 */
		virtual Type get_type(LookupFunction lookup=0,const void *data=0) const {return get_value(lookup,data).get_type(lookup,data);} 
	private:
		unsigned char _cur_child;	//!< Représente le numéro de l'argument à ajouter lorsque la fonction Function::add_child est appelée. Ceci n'est utile que si la fonction est créée initialement sans argument et que le programmeur les ajoute à la main.
		unsigned char _nbchildren;	//!< Nombre d'enfants du noeud courant, ou nombre d'arguments de la fonction
		SyntaxNode **_children;	//!< Enfants du noeud courant ou arguments de la fonction
		string _name;	//!< Nom de la fonction
};

/*****************************************/
/* DEFINITION DE LA GRAMMAIRE DU LANGAGE */
/*****************************************/
extern const unsigned char MAX_ARGS;	//!< Nombre maximal d'arguments des fonctions dans les expressions mathématiques

/**
 * \fn SyntaxNode *get_E(const string &source,size_t &num,unsigned char priority)
 * \brief Lit une expression partielle depuis une chaîne de caractères
 *
 * La fonction lit une expression depuis une chaîne de caractères en commençant à la position spécifiée. L'expression correspond à une juxtaposition de termes mathématiques au niveau de priorité priority. Par exemple, pour la priorité 2, l'expression est une somme ou une différence de produits. En priorité 3, l'expression est un produit ou un quotient de facteurs. En priorité 4, il s'agit d'une puissance de termes. Voir la grammaire BNF du langage définie dans \ref parserdoc.
 * Les caractères blancs sont ignorés dans la chaîne de caractères. La lecture s'interrompt si la fin de la chaîne est rencontrée et une exception est soulevée si d'autres identifiants sont attendus.
 * La position de lecture num est mise à jour avec la position suivant la fin de l'expression.
 * \param source Chaîne de caractères à lire
 * \param num Position où doit commencer la lecture. L'argument est mis à jour avec la nouvelle position à la fin de la lecture, c'est-à-dire la position du premier caractère après l'expression.
 * \param priority Niveau de priorité de l'expression, 1 par défaut qui correspond à l'expression mathématique la plus générale
 * \return Arbre syntaxique contenant la représentation de l'expression
 */
extern SyntaxNode *get_E(const string &source,size_t &num,unsigned char priority=1);

/**
 * \fn SyntaxNode *get_T(const string &source,size_t &num)
 * \brief Lit un terme depuis une chaîne de caractères
 *
 * La fonction lit un terme depuis une chaîne de caractères en commençant à la position spécifiée. Le terme est une valeur numérique ou une fonction appliquée à une ou plusieurs expressions, ou une expression entre parenthèses. Voir la grammaire BNF du langage définie dans \ref parserdoc pour plus d'informations. Les caractères blancs sont ignorés dans la chaîne de caractères. La lecture s'interrompt si la fin de la chaîne est rencontrée et une exception est soulevée si d'autres identifiants sont attendus.
 * La position de lecture num est mise à jour avec la position suivant la fin du terme.
 * Si le terme est une valeur, celle-ci peut être soit une chaîne de caractères, soit un nombre flottant. La chaîne de caractères est délimitée par des guillemets doubles. Si elle doit elle-même contenir des guillemets, ceux-ci sont doublés. Ex : "Ceci est une ""valeur""". Pour les flottants, toutes les écritures reconnaissables par l'analyseur contenu dans la fonction operator>> de la classe istringstream du C++ sont admises.
 * \param source Chaîne de caractères à lire
 * \param num Position où doit commencer la lecture. L'argument est mis à jour avec la nouvelle position à la fin de la lecture, c'est-à-dire la position du premier caractère après le terme
 * \return Arbre syntaxique contenant la représentation du terme
 */
extern SyntaxNode *get_T(const string &source,size_t &num);

/**
 * \fn void get_L(const string &source,size_t &num,SyntaxNode **args,unsigned char &nbargs)
 * \brief Lit une liste d'expressions depuis une chaîne de caractères
 *
 * La fonction lit une liste d'expressions depuis une chaîne de caractères en commençant à la position spécifiée. La liste d'expressions est une juxtaposition d'expressions séparées par des virgules. Voir aussi la grammaire BNF du langage définie dans \ref parserdoc pour plus d'informations. Les caractères blancs sont ignorés dans la chaîne de caractères. La lecture s'interrompt si la fin de la chaîne est rencontrée et une exception est soulevée si d'autres identifiants sont attendus. Le nombre maximal de termes de la liste est défini par la variable AST::MAX_ARGS.
 * \param source Chaîne de caractères à lire
 * \param num Position où doit commencer la lecture. L'argument est mis à jour avec la nouvelle position à la fin de la lecture, c'est-à-dire la position du premier caractère après la liste d'expressions
 * \param args Tableau d'arbres syntaxiques contenant les représentations de chacune des expressions lues
 * \param nbargs Nombre d'arguments lus
 */
extern void get_L(const string &source,size_t &num,SyntaxNode **args,unsigned char &nbargs);

}

#endif   // ----- #ifndef AST_H_INC  -----
